﻿using ArtMath.Attribute;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Flag;
using ArtMath.Helper;
using ArtMath.PointCollection;
using ArtMath.Resource;
using System;
using System.Collections.Generic;
using System.Drawing;

namespace ArtMath.Component.ConicalSection
{
    /// <summary>
    /// 焦点虚轴双曲线
    /// </summary>
    [Serializable]
    public class FocusImaginaryAxisHyperbola : HyperbolaBase
    {
        double c;
        public FocusImaginaryAxisHyperbola(SketchPad pad, string name, bool addToList = true) : base(pad, name, ToolTypeName.jdxzsqx, addToList)
        {
            InPoints = new PointBase[4];
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}1", "Focus")]
        public PointBase FocusPoint1
        {
            get { return InPoints[0]; }
            set { SetPoint(0, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}2", "Focus")]
        public PointBase FocusPoint2
        {
            get { return InPoints[1]; }
            set { SetPoint(1, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}+{1}1", "ImaginaryAxis", "EndPoint")]
        public PointBase VirtualPoint1
        {
            get { return InPoints[2]; }
            set { SetPoint(2, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}+{1}2", "ImaginaryAxis", "EndPoint")]
        public PointBase VirtualPoint2
        {
            get { return InPoints[3]; }
            set { SetPoint(3, value); }
        }
        public override PointD Focus1
        {
            get
            {
                if (FocusPoint1 != null) return FocusPoint1.ToPointD();
                return base.Focus1;
            }
        }
        public override PointD NewFocus1
        {
            get
            {
                if (FocusPoint1 != null) return FocusPoint1.NewXY;
                return base.NewFocus1;
            }
        }
        public override PointD PFocus1
        {
            get
            {
                if (FocusPoint1 != null) return FocusPoint1.Pxy;
                return base.PFocus1;
            }
        }
        public override PointD Focus2
        {
            get
            {
                if (FocusPoint2 != null) return FocusPoint2.ToPointD();
                return base.Focus2;
            }
        }
        public override PointD NewFocus2
        {
            get
            {
                if (FocusPoint2 != null) return FocusPoint2.NewXY;
                return base.NewFocus2;
            }
        }
        public override PointD PFocus2
        {
            get
            {
                if (FocusPoint2 != null) return FocusPoint2.Pxy;
                return base.PFocus2;
            }
        }
        public override double NewFocusAngle
        {
            get
            {
                return FocusPoint1.NewXY.GetAngle(FocusPoint2.NewXY);
            }
        }
        public override double FocalHalfLength
        {
            get
            {
                return c;
            }
        }
        public override double NewFocalHalfLength
        {
            get
            {
                return FocusPoint1.NewXY.DistanceTo(FocusPoint2.NewXY) / 2;
            }
        }
        public override PointD NewCenter
        {
            get
            {
                return (FocusPoint1.NewXY + FocusPoint2.NewXY) / 2;
            }
        }
        public override PointD NewPCenter
        {
            get
            {
                return (FocusPoint1.NewPxy + FocusPoint2.NewPxy) / 2;
            }
        }
        public override double NewImaginaryAxisHalfLength
        {
            get
            {
                return VirtualPoint1.NewXY.DistanceTo(VirtualPoint2.NewXY) / 2;
            }
        }
        public override double NewRealAxisHalfLength
        {
            get
            {
                double b = NewImaginaryAxisHalfLength, c = NewFocalHalfLength;
                return Math.Sqrt(c * c - b * b);
            }
        }
        public override PointCollectionBase[] GetInPointMovingRange(PointBase movePoint, Base sender = null)
        {
            switch (CountMovablePoints())
            {
                case 1:
                    if (movePoint == FocusPoint1)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(VirtualPoint1.NewXY + VirtualPoint2.NewXY - FocusPoint2.NewXY) };
                    }
                    else if (movePoint == FocusPoint2)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(VirtualPoint1.NewXY + VirtualPoint2.NewXY - FocusPoint1.NewXY) };
                    }
                    else if (movePoint == VirtualPoint1)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(FocusPoint1.NewXY + FocusPoint2.NewXY - VirtualPoint2.NewXY) };
                    }
                    else if (movePoint == VirtualPoint2)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(FocusPoint1.NewXY + FocusPoint2.NewXY - VirtualPoint1.NewXY) };
                    }
                    break;
                case 2:
                    if (movePoint == FocusPoint1)
                    {
                        if (FocusPoint2.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((VirtualPoint1.NewXY + VirtualPoint2.NewXY) / 2, -1 / VirtualPoint1.NewXY.GetSlope(VirtualPoint2.NewXY)) };
                        }
                        else if (VirtualPoint1.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(VirtualPoint2.NewXY, VirtualPoint2.NewXY.DistanceTo(FocusPoint2.NewXY), VirtualPoint2.NewXY.GetAngle(FocusPoint2.NewXY) + Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                        else if (VirtualPoint2.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(VirtualPoint1.NewXY, VirtualPoint1.NewXY.DistanceTo(FocusPoint2.NewXY), VirtualPoint1.NewXY.GetAngle(FocusPoint2.NewXY) + Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                    }
                    else if (movePoint == FocusPoint2)
                    {
                        if (FocusPoint1.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((VirtualPoint1.NewXY + VirtualPoint2.NewXY) / 2, -1 / VirtualPoint1.NewXY.GetSlope(VirtualPoint2.NewXY)) };
                        }
                        else if (VirtualPoint1.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(VirtualPoint2.NewXY, VirtualPoint2.NewXY.DistanceTo(FocusPoint1.NewXY), VirtualPoint2.NewXY.GetAngle(FocusPoint1.NewXY) + Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                        else if (VirtualPoint2.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(VirtualPoint1.NewXY, VirtualPoint1.NewXY.DistanceTo(FocusPoint1.NewXY), VirtualPoint1.NewXY.GetAngle(FocusPoint1.NewXY) + Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                    }
                    else if (movePoint == VirtualPoint1)
                    {
                        if (FocusPoint1.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(FocusPoint2.NewXY, FocusPoint2.NewXY.DistanceTo(VirtualPoint2.NewXY), FocusPoint2.NewXY.GetAngle(VirtualPoint2.NewXY) - Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                        else if (FocusPoint2.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(FocusPoint1.NewXY, FocusPoint1.NewXY.DistanceTo(VirtualPoint2.NewXY), FocusPoint1.NewXY.GetAngle(VirtualPoint2.NewXY) - Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                        else if (VirtualPoint2.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((FocusPoint1.NewXY + FocusPoint2.NewXY) / 2, -1 / FocusPoint1.NewXY.GetSlope(FocusPoint2.NewXY)) };
                        }
                    }
                    else if (movePoint == VirtualPoint2)
                    {
                        if (FocusPoint1.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(FocusPoint2.NewXY, FocusPoint2.NewXY.DistanceTo(VirtualPoint1.NewXY), FocusPoint2.NewXY.GetAngle(VirtualPoint1.NewXY) - Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                        else if (FocusPoint2.Movable)
                        {
                            return new PointCollectionBase[] { new PartialCircle(FocusPoint1.NewXY, FocusPoint1.NewXY.DistanceTo(VirtualPoint1.NewXY), FocusPoint1.NewXY.GetAngle(VirtualPoint1.NewXY) - Core.Helper.Angle.RightAngle, Math.PI) };
                        }
                        else if (VirtualPoint1.Movable)
                        {
                            return new PointCollectionBase[] { new StraightLine((FocusPoint1.NewXY + FocusPoint2.NewXY) / 2, -1 / FocusPoint1.NewXY.GetSlope(FocusPoint2.NewXY)) };
                        }
                    }
                    break;
            }
            return base.GetInPointMovingRange(movePoint, sender);
        }
        public override void InternalPointMove(PointBase movePoint, Base sender = null)
        {
            switch (CountMovablePoints())
            {
                case 2:
                    if (movePoint == FocusPoint1)
                    {
                        if (FocusPoint2.Movable)
                        {
                            FocusPoint2.Move(VirtualPoint1.NewPxy + VirtualPoint2.NewPxy - movePoint.NewPxy, true);
                        }
                        else if (VirtualPoint1.Movable)
                        {
                            VirtualPoint1.Move(FocusPoint2.NewPxy + movePoint.NewPxy - VirtualPoint2.NewPxy, true);
                        }
                        else if (VirtualPoint2.Movable)
                        {
                            VirtualPoint2.Move(movePoint.NewPxy + FocusPoint2.NewPxy - VirtualPoint1.NewPxy, true);
                        }
                    }
                    else if (movePoint == FocusPoint2)
                    {
                        if (FocusPoint1.Movable)
                        {
                            FocusPoint1.Move(VirtualPoint1.NewPxy + VirtualPoint2.NewPxy - movePoint.NewPxy, true);
                        }
                        else if (VirtualPoint1.Movable)
                        {
                            VirtualPoint1.Move(movePoint.NewPxy + FocusPoint1.NewPxy - VirtualPoint2.NewPxy, true);
                        }
                        else if (VirtualPoint2.Movable)
                        {
                            VirtualPoint2.Move(FocusPoint1.NewPxy + movePoint.NewPxy - VirtualPoint1.NewPxy, true);
                        }
                    }
                    else if (movePoint == VirtualPoint1)
                    {
                        if (FocusPoint1.Movable)
                        {
                            FocusPoint1.Move(movePoint.NewPxy + VirtualPoint2.NewPxy - FocusPoint2.NewPxy, true);
                        }
                        else if (FocusPoint2.Movable)
                        {
                            FocusPoint2.Move(movePoint.NewPxy + VirtualPoint2.NewPxy - FocusPoint1.NewPxy, true);
                        }
                        else if (VirtualPoint2.Movable)
                        {
                            VirtualPoint2.Move(FocusPoint1.NewPxy + FocusPoint2.NewPxy - movePoint.NewPxy, true);
                        }
                    }
                    else if (movePoint == VirtualPoint2)
                    {
                        if (FocusPoint1.Movable)
                        {
                            FocusPoint1.Move(movePoint.NewPxy + VirtualPoint1.NewPxy - FocusPoint2.NewPxy, true);
                        }
                        else if (FocusPoint2.Movable)
                        {
                            FocusPoint2.Move(VirtualPoint1.NewPxy + movePoint.NewPxy - FocusPoint1.NewPxy, true);
                        }
                        else if (VirtualPoint1.Movable)
                        {
                            VirtualPoint1.Move(FocusPoint2.NewPxy + FocusPoint1.NewPxy - movePoint.NewPxy, true);
                        }
                    }
                    return;
            }
            base.InternalPointMove(movePoint, sender);
        }
        public override void ComponentChanged(ShapeBase component)
        {
            //pske.Center = NewPCenter;
            //ske.Center = NewCenter;
            c = NewFocalHalfLength;
            //ske.RotateAngle = NewFocusAngle;
            //ImaginaryAxisHalfLength = NewImaginaryAxisHalfLength;
            //RealAxisHalfLength = NewRealAxisHalfLength;
            base.ComponentChanged(component);
        }
        public override void ComponentBuilding(Base component)
        {
            PointD xy;
            switch (OrderIndex)
            {
                case 0:
                    if (FocusPoint1 == null) return;
                    if (FocusPoint2 != null)
                    {
                        SpareCoordinate = SpareCoordinate.GetProjectivePoint((FocusPoint1.Pxy + FocusPoint2.Pxy) / 2,
                            Pad.GetVerticalLinePSlope(FocusPoint1.Pxy, FocusPoint2.Pxy));
                        xy = Pad.PxyToXY(SpareCoordinate);
                        ImaginaryAxisHalfLength = Center.DistanceTo(xy);
                    }
                    else
                    {
                        pske.Center = (FocusPoint1.Pxy + SpareCoordinate) / 2;
                        xy = Pad.PxyToXY(SpareCoordinate);
                        ske.Center = (FocusPoint1.ToPointD() + xy) / 2;
                        c = Center.DistanceTo(xy);
                        FocusAngle = FocusPoint1.ToPointD().GetAngle(xy);
                        ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}{Resources.LeftParenthesis}{Resources.JoinLocalizedString("Hyperbola", "Center")}{Resources.ColonSeparate}{Pad.ShowPoint(Center)}{Resources.CommaSeparate}{Resources.Translate("FocalHalfLength")} = {FocalHalfLength}）");
                        return;
                    }
                    break;
                case 1:
                    if (VirtualPoint1 == null) return;
                    if (VirtualPoint2 != null)
                    {
                        SpareCoordinate = SpareCoordinate.GetProjectivePoint((VirtualPoint1.Pxy + VirtualPoint2.Pxy) / 2,
                            Pad.GetVerticalLinePSlope(VirtualPoint1.Pxy, VirtualPoint2.Pxy));
                        xy = Pad.PxyToXY(SpareCoordinate);
                        c = Center.DistanceTo(xy);
                    }
                    else
                    {
                        pske.Center = (VirtualPoint1.Pxy + SpareCoordinate) / 2;
                        xy = Pad.PxyToXY(SpareCoordinate);
                        ske.Center = (VirtualPoint1.ToPointD() + xy) / 2;
                        double k = VirtualPoint1.ToPointD().GetSlope(xy);
                        FocusAngle = Math.Atan(-1 / k);
                        if (ske.RotateAngle < 0) ske.RotateAngle += Math.PI;
                        ImaginaryAxisHalfLength = Center.DistanceTo(xy);
                        ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}{Resources.LeftParenthesis}{Resources.JoinLocalizedString("Hyperbola", "Center")}{Resources.ColonSeparate}{Pad.ShowPoint(Center)}{Resources.CommaSeparate}{Resources.Translate("ImaginaryAxisHalfLength")} = {ImaginaryAxisHalfLength}）");
                        return;
                    }
                    break;
                case 2:
                    if (FocusPoint1 == null) return;
                    if (VirtualPoint1 != null && FocusPoint2 == null)//FocusPoint2 == null不可少
                    {
                        xy = Pad.PxyToXY(SpareCoordinate);
                        double k = FocusPoint1.ToPointD().GetSlope(xy);
                        ske.Center = Utility.GetCrossPoint(FocusPoint1.ToPointD(), k, VirtualPoint1.ToPointD(), -1 / k);
                        pske.Center = Pad.XYToPxy(Center);
                        SpareCoordinate = 2 * PCenter - FocusPoint1.Pxy;
                        FocusAngle = FocusPoint1.ToPointD().GetAngle(xy);
                        c = Center.DistanceTo(FocusPoint1.ToPointD());
                        ImaginaryAxisHalfLength = Center.DistanceTo(VirtualPoint1.ToPointD());
                    }
                    else
                    {
                        ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}");
                        return;
                    }
                    break;
            }
            RealAxisHalfLength = Math.Sqrt(c * c - ImaginaryAxisHalfLength * ImaginaryAxisHalfLength);
            //PFocus1 = Center.Offset(-RotateAngle, FocalHalfLength);
            //PFocus2 = Center.Offset(Math.PI - RotateAngle, FocalHalfLength);
            //if (Pad.Coordinate != null)
            //{
            //    PFocus1 = Pad.Coordinate.XYToPxy(PFocus1);
            //    PFocus2 = Pad.Coordinate.XYToPxy(PFocus2);
            //}
            base.ComponentBuilding(component);
        }
        public override bool CanDrawVirtual
        {
            get
            {
                switch (OrderIndex)
                {
                    case 0:
                        if (FocusPoint2 != null)
                        {
                            return true;
                        }
                        break;
                    case 1:
                        if (VirtualPoint2 != null)
                        {
                            return true;
                        }
                        break;
                    case 2:
                        if (VirtualPoint1 != null)
                        {
                            return true;
                        }
                        break;
                }
                return false;
            }
        }
        public override void PaintVirtualObjects(Graphics gra)
        {
            if (CanDrawVirtual)
            {
                gra.DrawPoint(2 * PCenter - (OrderIndex == 0 || OrderIndex == 1 ? SpareCoordinate_ : VirtualPoint1.Pxy));
            }
            base.PaintVirtualObjects(gra);
        }
        protected override void ClickOrder(IList<PointCreatingArgs> args, int clickTimes, Predicate<PointCreatingArgs> act)
        {
            if (act == null) return;
            switch (OrderIndex)
            {
                case 1:
                    if (!act(args[2])) return;
                    if (!act(args[3])) return;
                    if (!act(args[0])) return;
                    if (!act(args[1])) return;
                    return;
                case 2:
                    if (!act(args[0])) return;
                    if (!act(args[2])) return;
                    if (!act(args[1])) return;
                    if (!act(args[3])) return;
                    return;
            }
            base.ClickOrder(args, clickTimes, act);
        }
        public override void CreateComponents()
        {
            switch (OrderIndex)
            {
                case 0:
                    if (FocusPoint1 == null)
                    {
                        FocusPoint1 = Pad.CreatePoint($"{Resources.Translate("Focus")}1", SpareCoordinate_);
                        Pad.TrackObj = this;
                    }
                    else if (FocusPoint2 == null)
                    {
                        FocusPoint2 = Pad.CreatePoint($"{Resources.Translate("Focus")}2", SpareCoordinate_, true, new PointCollectionBase[] { new Universal(FocusPoint1.ToPointD()) });
                    }
                    else
                    {
                        double angle = FocusPoint1.ToPointD().GetAngle(FocusPoint2.ToPointD());
                        VirtualPoint1 = Pad.CreatePoint($"{Resources.Translate("ImaginaryAxis")}{Resources.Join}{Resources.Translate("EndPoint")}1", SpareCoordinate_, true, new PointCollectionBase[] { new LineSegment(Center.Offset(angle + Core.Helper.Angle.RightAngle, FocalHalfLength), Center.Offset(angle - Core.Helper.Angle.RightAngle, FocalHalfLength)) { Exceptions = new HashSet<PointCollectionBase>() { new LineSegment(FocusPoint1.ToPointD(), FocusPoint2.ToPointD()) } } });
                        Flags.ShieldCtrl(() => { VirtualPoint2 = Pad.CreatePoint($"{Resources.Translate("ImaginaryAxis")}{Resources.Join}{Resources.Translate("EndPoint")}2", 2 * PCenter - VirtualPoint1.Pxy, false); });
                        base.CreateComponents();
                    }
                    break;
                case 1:
                    if (VirtualPoint1 == null)
                    {
                        VirtualPoint1 = Pad.CreatePoint($"{Resources.Translate("ImaginaryAxis")}{Resources.Join}{Resources.Translate("EndPoint")}1", SpareCoordinate_);
                        Pad.TrackObj = this;
                    }
                    else if (VirtualPoint2 == null)
                    {
                        VirtualPoint2 = Pad.CreatePoint($"{Resources.Translate("ImaginaryAxis")}{Resources.Join}{Resources.Translate("EndPoint")}2", SpareCoordinate_, true, new PointCollectionBase[] { new Universal(VirtualPoint1.ToPointD()) });
                    }
                    else
                    {
                        double angle = VirtualPoint1.ToPointD().GetAngle(VirtualPoint2.ToPointD()),
                            len = VirtualPoint1.DistanceTo(VirtualPoint2) / 2;
                        PointD pt1 = Center.Offset(angle + Core.Helper.Angle.RightAngle, len), pt2 = Center.Offset(angle - Core.Helper.Angle.RightAngle, len);
                        FocusPoint1 = Pad.CreatePoint($"{Resources.Translate("Focus")}1", SpareCoordinate_, true, new PointCollectionBase[] {
                            new Ray(pt1, Center.GetAngle(pt1) ),
                            new Ray(pt2, Center.GetAngle(pt2) ) });
                        Flags.ShieldCtrl(() => { FocusPoint2 = Pad.CreatePoint($"{Resources.Translate("Focus")}2", 2 * PCenter - FocusPoint1.Pxy, false); });
                        base.CreateComponents();
                    }
                    break;
                case 2:
                    if (FocusPoint1 == null)
                    {
                        FocusPoint1 = Pad.CreatePoint($"{Resources.Translate("Focus")}1", SpareCoordinate_);
                        Pad.TrackObj = this;
                    }
                    else if (VirtualPoint1 == null)
                    {
                        VirtualPoint1 = Pad.CreatePoint($"{Resources.Translate("ImaginaryAxis")}{Resources.Join}{Resources.Translate("EndPoint")}1", SpareCoordinate_, true, new PointCollectionBase[] { new Universal(FocusPoint1.ToPointD()) });
                    }
                    else
                    {
                        FocusPoint2 = Pad.CreatePoint($"{Resources.Translate("Focus")}2", SpareCoordinate_, true, new PointCollectionBase[] { new PartialCircle(VirtualPoint1.ToPointD(), FocusPoint1.DistanceTo(VirtualPoint1), VirtualPoint1.ToPointD().GetAngle(FocusPoint1.ToPointD()) + Core.Helper.Angle.RightAngle, Math.PI) });
                        Flags.ShieldCtrl(() => { VirtualPoint2 = Pad.CreatePoint($"{Resources.Translate("ImaginaryAxis")}{Resources.Join}{Resources.Translate("EndPoint")}2", 2 * PCenter - VirtualPoint1.Pxy, false); });
                        base.CreateComponents();
                    }
                    break;
            }
        }
    }
}
